home *** CD-ROM | disk | FTP | other *** search
/ CDUTIL 13 / CDUTIL #13 Julio 1995.iso / windows / acadcom / acrx / sample / colext.cc < prev    next >
Encoding:
Text File  |  1995-02-08  |  73.8 KB  |  2,362 lines

  1. /* Next available MSG number is  66 */
  2.  
  3. /*    COLEXT.CPP
  4.  
  5.    Copyright (C) 1992, 1993, 1994 by Autodesk, Inc.
  6.  
  7.    Permission to use, copy, modify, and distribute this software in 
  8.    object code form for any purpose and without fee is hereby granted, 
  9.    provided that the above copyright notice appears in all copies and 
  10.    that both that copyright notice and the limited warranty and 
  11.    restricted rights notice below appear in all supporting 
  12.    documentation.
  13.  
  14.    AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.  
  15.    AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 
  16.    MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
  17.    DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 
  18.    UNINTERRUPTED OR ERROR FREE.
  19.  
  20.    Use, duplication, or disclosure by the U.S. Government is subject to 
  21.    restrictions set forth in FAR 52.227-19 (Commercial Computer 
  22.    Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 
  23.    (Rights in Technical Data and Computer Software), as applicable.
  24.     
  25.    .
  26.  
  27.       DESCRIPTION:
  28.  
  29.         AutoCAD colour manipulation functions
  30.  
  31.         Designed and implemented in October of 1989 by John Walker
  32.  
  33.         This ADS application permits AutoCAD colours to  be  specified
  34.         in  any  of  a  number  of  commonly-used colour systems.  The
  35.         application provides AutoLisp functions for each colour system
  36.         which  accept  the  parameters  which  define a colour in that
  37.         system and return the AutoCAD colour number from the  standard
  38.         palette  for  256  colour  devices which best approximates the
  39.         requested colour.
  40.  
  41.         In  addition, functions are provided to convert either AutoCAD
  42.         colour indices  or  Red-Green-Blue  colour  triples  to  their
  43.         representation in each of the colour systems.
  44.  
  45.         Finally, functions which convert  colours  in  non-RGB  colour
  46.         systems to RGB triples are provided.
  47.  
  48.  
  49.         COLOUR SYSTEMS
  50.         ==============
  51.  
  52.         The colour systems implemented are:
  53.  
  54.         RGB      Colours  are  specified  as the  intensities  of  the
  55.                  three  additive  primary colours Red, Green, and Blue
  56.                  which generate the colour.  The intensities are given
  57.                  in the range from 0 to 1, with 0 indicating no  light
  58.                  of  that colour and 1 representing maximum intensity.
  59.  
  60.         CMY      Colours  are  specified by  the  intensities  of  the
  61.                  subtractive   primary   colours  Cyan,  Magenta,  and
  62.                  Yellow.  The CMY system is used in composing ink  and
  63.                  toner  mixtures  for  subtractive printing processes.
  64.                  Intensities are specified in the range from 0  to  1,
  65.                  with  0  indicating  none  of  the  specified pigment
  66.                  present and 1 indicating the maximum amount.
  67.  
  68.         YIQ      The  YIQ  system  is  used   to  encode  colours  for
  69.                  television broadcasting.  The YIQ system  remaps  the
  70.                  RGB  space such that Y represents a primary scaled to
  71.                  the human luminosity  response  curve.   Two  colours
  72.                  with the same Y values will be indistinguishable when
  73.                  viewed on a monochrome monitor; to guarantee  colours
  74.                  are  distinct  when viewed in monochrome, they should
  75.                  be converted to YIQ and  checked  for  a  substantial
  76.                  difference  in  Y.   Y  ranges from 0 to 1, with zero
  77.                  indicating black and 1 maximum intensity.  Since  the
  78.                  YIQ system is a remapping of the RGB colour cube by a
  79.                  nontrivial affine transformation, the I and Q  values
  80.                  in  the  YIQ  system do not "come out even"; I ranges
  81.                  from -0.6 to 0.6, and Q ranges from  -0.52  to  0.52.
  82.  
  83.         HSV      The HSV system approximates the intuitive concepts of
  84.                  hue  (tint),  saturation  (shade), and value (tone or
  85.                  brightness), by mapping colours into a hexcone.   Hue
  86.                  is  specified  by  a number from 0 to 1, representing
  87.                  the  angle  around  the hue circle in fraction of the
  88.                  circumference of the hue wheel with red at 0,  yellow
  89.                  at  1/6,  and  so  on.   Saturation is expressed as a
  90.                  number from 0 to  1,  with  0  indicating  a  totally
  91.                  desaturated  shade  (grey  scale), and 1 a completely
  92.                  saturated  shade  (no  admixture  of  white).   Value
  93.                  expresses intensity from 0 to 1, with zero indicating
  94.                  black and 1 maximum intensity.
  95.  
  96.         HLS      The  HLS system encodes the intuitive concepts of hue
  97.                  (tint),   lightness   (intensity),   and   saturation
  98.                  (shade), by mapping colours into  a  double  hexcone.
  99.                  The  HLS system is closely related to the HSV system,
  100.                  and can be thought of as the result of stretching the
  101.                  flat   end   of   the  HSV  hexcone  upward  until  a
  102.                  symmetrical   double   hexcone  is  formed.   Hue  is
  103.                  specified by a number from 0 to 1,  representing  the
  104.                  angle  around  the  hue  circle  in  fraction  of the
  105.                  circumference of the hue wheel with red at 0,  yellow
  106.                  at  1/6, and so on.  Lightness expresses intensity as
  107.                  a number from 0 to 1, with zero indicating black  and
  108.                  1  maximum  intensity.   Saturation is expressed as a
  109.                  number from 0 to  1,  with  0  indicating  a  totally
  110.                  desaturated  shade  (grey  scale), and 1 a completely
  111.                  saturated shade (no admixture of white).
  112.  
  113.         CTEMP    The  CTEMP  system  specifies  colours  emitted  by a
  114.                  Planckian  (black  body)  radiator   with   a   given
  115.                  temperature   in   degrees  Kelvin.   Typical  colour
  116.                  temperatures are:
  117.  
  118.                     The star Spica                  28000 K
  119.                     The star Sirius                 10700 K
  120.                     North sky light                  7500 K
  121.                     Average daylight                 6500 K
  122.                     Xenon lamp                       6000 K
  123.                     Typical sunlight + skylight      5500 K
  124.                     The star Betelgeuse              3400 K
  125.                     Tungsten/halogen lamps           3300 K
  126.                     Incandescent bulbs (100-200 W)   2900 K
  127.                     Sunlight at sunset               2000 K
  128.                     Candle flame                     1900 K
  129.  
  130.         CNS      The CNS system expresses colours as English language
  131.                  names.
  132.  
  133.                  A colour is specified in the CNS system by a sequence
  134.                  of  English  words.   CNS  colours  may be achromatic
  135.                  (grey scale values) or chromatic.  Chromatic  colours
  136.                  consist  of  a  hue  (dominant  spectral  component),
  137.                  saturation (the extent of dilution with  white),  and
  138.                  lightness  (intensity).   A chromatic hue is composed
  139.                  by naming and mixing the following primary hues:
  140.  
  141.                     Red, Orange/Brown, Yellow, Green, Blue, Purple
  142.  
  143.                  and secondary hues:
  144.  
  145.                     Reddish, Orangish/Brownish, Yellowish,
  146.                     Greenish, Bluish, Purplish
  147.  
  148.                  To  obtain  one of the primary hues, just specify its
  149.                  name,  e.g.   "Yellow".   To  obtain  a  hue  halfway
  150.                  between  two  primary  hues, compose the two bounding
  151.                  hues: for example "Yellow-green" (or  "Green-yellow";
  152.                  it  doesn't  matter  which  is  specified first).  To
  153.                  obtain a hue one quarter the distance from one colour
  154.                  to  an adjacent colour, compose the "ish" form of the
  155.                  adjacent  colour  with  the  primary   colour.    For
  156.                  example, the hues between Yellow and Green are named:
  157.  
  158.                     Yellow
  159.                     Greenish yellow
  160.                     Yellow-green (or Green-yellow)
  161.                     Green
  162.  
  163.                  Brown  is  a  somewhat  confusing  special case.  The
  164.                  colour we perceive as  brown  has  the  same  hue  as
  165.                  orange  but  when  seen  with  reduced saturation and
  166.                  intensity it appears as brown, a colour distinct from
  167.                  orange  (that's  why there's no brown in the rainbow,
  168.                  in case you've ever lost sleep pondering that  fact).
  169.                  To  compensate for this perceptual quirk, "brown" and
  170.                  "brownish" may be used as synonyms for  "orange"  and
  171.                  "orangish"  when  specifying  hues.   If  "brown"  or
  172.                  "brownish"  are  used,  the  default  saturation  and
  173.                  lightness  (see  below)  are  set  so  the orange hue
  174.                  appears brown; if explicit saturation  and  lightness
  175.                  are given orange and brown are synonymous.
  176.  
  177.                  Lightness  (brightness or intensity) may be specified
  178.                  by adding one of  the  following  adjectives  to  the
  179.                  colour name:
  180.  
  181.                     very dark
  182.                     dark
  183.                     medium
  184.                     light
  185.                     very light
  186.  
  187.                  If  no  lightness  adjective  appears,  a  default is
  188.                  assumed (unless a brown hue was named, in which  case
  189.                  the default will be "light").  This diverges from the
  190.                  CNS specification in which omitted lightness defaults
  191.                  to medium intensity.
  192.  
  193.                  Saturation (the degree of admixture of  white  light)
  194.                  is specified by the following adjectives:
  195.  
  196.                     grayish (or greyish)
  197.                     moderate
  198.                     strong
  199.                     vivid
  200.  
  201.                  "Vivid" denotes a fully saturated colour, and is  the
  202.                  default  (unless  a brown is specified, in which case
  203.                  the default saturation is "strong").
  204.  
  205.                  Examples of chromatic colour specifications are:
  206.  
  207.                     red
  208.                     blue-green
  209.                     purplish red
  210.                     very dark green
  211.                     strong yellow-green
  212.                     very light grayish greenish yellow
  213.  
  214.                  the last  describing  the  colour  of  snow  I  don't
  215.                  recommend you eat.
  216.  
  217.                  Achromatic  specifications describe 7 shades of grey,
  218.                  to wit:
  219.  
  220.                     black
  221.                     very dark gray
  222.                     dark gray
  223.                     gray (or medium gray)
  224.                     light gray
  225.                     very light gray
  226.                     white
  227.  
  228.                  in all cases "grey" may be used instead of "gray".
  229.  
  230.                  Although the word order used herein is as  prescribed
  231.                  by the formal specification of CNS, my implementation
  232.                  is  totally  insensitive  to  word  order.   You  can
  233.                  specify  "yellow  greyish light greenish very" if you
  234.                  like, silly seems how notwithstanding it.
  235.  
  236.  
  237.         AUTOLISP-CALLABLE FUNCTIONS
  238.         ===========================
  239.  
  240.         Three groups of AutoLisp-callable functions  are  implemented.
  241.         The first convert specifications in external colour systems to
  242.         AutoCAD's internal colour indices.  These  functions  map  the
  243.         specifications  into either AutoCAD's standard 8 or 256 colour
  244.         palette.  The palette is selected with the (COLSET) function:
  245.  
  246.            (COLSET <gamut>)
  247.  
  248.         where  <gamut>  is  either  8  or 256 to choose the colour set
  249.         desired.  (COLSET) returns the current colour gamut; if called
  250.         with  no  arguments, (COLSET) returns the current colour gamut
  251.         without changing it.  The following functions  return  AutoCAD
  252.         colour indices between 1 and <gamut> - 1.
  253.  
  254.            (CMY   <cyan> <magenta> <yellow>)
  255.            (CMY '(<cyan> <magenta> <yellow>))
  256.  
  257.            (CNS "CNS colour name description")
  258.  
  259.            (CTEMP <temperature>)
  260.  
  261.            (HLS   <hue> <lightness> <saturation>)
  262.            (HLS '(<hue> <lightness> <saturation>))
  263.  
  264.            (HSV   <hue> <saturation> <value>)
  265.            (HSV '(<hue> <saturation> <value>))
  266.  
  267.            (RGB   <red> <green> <blue>)
  268.            (RGB '(<<red> <green> <blue>))
  269.  
  270.            (YIQ   <Y-value> <I-value> <Q-value>)
  271.            (YIQ '(<Y-value> <I-value> <Q-value>))
  272.  
  273.         Except for the (CNS) function, which takes a string  argument,
  274.         and  (CTEMP)  which  takes  a  single numeric temperature, all
  275.         these  conversion  functions  accept  either  three  numerical
  276.         arguments  (either  integer  or  real),  or  a  list  of three
  277.         numbers.  Representing colour triples as lists,  in  the  same
  278.         manner as three-dimensional point co-ordinates, allows them to
  279.         be manipulated  as  units  and  operated  upon  with  AutoLisp
  280.         functions.  For example the (distance) function can be used to
  281.         determine distance in colour space  as  well  as  in  physical
  282.         space.  If invalid arguments are passed to these functions, an
  283.         error message is displayed and nil  is  returned.   The  (CNS)
  284.         function,  which can generate a wide variety of error messages
  285.         resulting from syntax errors  in  the  string  passed  to  it,
  286.         indicates  an error by returning nil.  A string describing the
  287.         most recent error  detected  by  the  (CNS)  function  can  be
  288.         obtained  by  calling (CNSERR).  If no error has been detected
  289.         by (CNS), (CNSERR) returns nil.
  290.  
  291.         When passed valid arguments, all  of  these  functions  return
  292.         AutoCAD  colour  numbers  ranging  from  1  to  255.  They may
  293.         therefore be specified at any AutoCAD prompt which requests  a
  294.         colour number.
  295.  
  296.         A   second   group   of  functions  converts  external  colour
  297.         specifications to lists of RGB  intensities.   Each  of  these
  298.         functions  takes  the  same  arguments  as the functions which
  299.         return AutoCAD colour indices.
  300.  
  301.            (CMY-RGB   <cyan> <magenta> <yellow>)
  302.            (CMY-RGB '(<cyan> <magenta> <yellow>))
  303.  
  304.            (CNS-RGB "CNS colour name description")
  305.  
  306.            (CTEMP-RGB <temperature>)
  307.  
  308.            (HLS-RGB   <hue> <lightness> <saturation>)
  309.            (HLS-RGB '(<hue> <lightness> <saturation>))
  310.  
  311.            (HSV-RGB   <hue> <saturation> <value>)
  312.            (HSV-RGB '(<hue> <saturation> <value>))
  313.  
  314.            (YIQ-RGB   <Y-value> <I-value> <Q-value>)
  315.            (YIQ-RGB '(<Y-value> <I-value> <Q-value>))
  316.  
  317.         There  is  no RGB-RGB function; it would be simply an identity
  318.         function.
  319.  
  320.         The  third family of functions converts AutoCAD colour indices
  321.         from 0 to 255 or RGB triples to their representation  in  each
  322.         of  the  external  colour  systems.   AutoCAD  colour  index 0
  323.         (black), which cannot be specified as  an  entity  colour,  is
  324.         nonetheless a valid argument to these functions.
  325.  
  326.            (TO-CMY <colour>)
  327.            (TO-CNS <colour>)
  328.            (TO-HLS <colour>)
  329.            (TO-HSV <colour>)
  330.            (TO-RGB <colour>)
  331.            (TO-YIQ <colour>)
  332.  
  333.         With  the  exception  of  (TO-CNS), which returns a CNS colour
  334.         specification string, all of these functions return a list  of
  335.         three  real numbers specifying the values in its colour system
  336.         corresponding to the AutoCAD colour index or RGB  triple.   If
  337.         an  RGB  triple  is  specified for <colour> it may be given as
  338.         three arguments or as a list of three numbers.
  339.  
  340.  
  341.         INTERNAL FUNCTIONS
  342.         ==================
  343.  
  344.         Internal conversion functions implemented in this  module  are
  345.         as  described  below.  Definitions are given as prototypes for
  346.         readability;  for  compatibility  with  older  compilers,  the
  347.         actual  code  is  not  prototyped.  All conversions are to and
  348.         from RGB--to get between two non-RGB systems, you must convert
  349.         through RGB.
  350.  
  351.                                 CMY
  352.  
  353.         void rgb_cmy(ads_real r, ads_real g, ads_real b,
  354.                      ads_real *c, ads_real *m, ads_real *y)
  355.            Converts r, g, b (0 to 1) to c, m, y (0 to 1).
  356.  
  357.         void cmy_rgb(ads_real c, ads_real m, ads_real y,
  358.                      ads_real *r, ads_real *g, ads_real *b)
  359.            Converts c, m, y (0 to 1) to r, g, b (0 to 1).
  360.  
  361.                                CTEMP
  362.  
  363.         void ctemp_rgb(ads_real temperature,
  364.                        ads_real *r, ads_real *g, ads_real *b)
  365.            Converts a colour temperature specified in degrees Kelvin,
  366.            to r, g, b (0 to 1).
  367.  
  368.                                 YIQ
  369.  
  370.         void rgb_yiq(ads_real r, ads_real g, ads_real b,
  371.                      ads_real *y, ads_real *i, ads_real *q)
  372.            Converts r, g, b (0 to 1) to y (0 to 1), i (-0.6 to 0.6),
  373.            and q (-0.52 to 0.52).
  374.  
  375.         void yiq_rgb(ads_real y, ads_real i, ads_real q,
  376.                      ads_real *r, ads_real *g, ads_real *b)
  377.            Converts y (0 to 1), i (-0.6 to 0.6), and q (-0.52 to 0.52)
  378.            to r, g, b (0 to 1).
  379.  
  380.                                 HSV
  381.  
  382.         void rgb_hsv(ads_real r, ads_real g, ads_real b,
  383.                      ads_real *h, ads_real *s, ads_real *v)
  384.            Converts r, g, b (0 to 1) to h (0 to 360), s (0 to 1),  and
  385.            v  (0  to  1).  Note that rgb_hsv() returns hue in terms of
  386.            degrees, not as a  fraction  of  circumference  as  do  the
  387.            AutoLisp-callable functions.
  388.  
  389.         void hsv_rgb(ads_real h, ads_real s, ads_real v,
  390.                      ads_real *r, ads_real *g, ads_real *b)
  391.            Converts  h (0 to 360), s (0 to 1), and v (0 to 1) to r, g,
  392.            b (0 to 1).  Note that rgb_hsv() expects hue  in  terms  of
  393.            degrees,  not  as  a  fraction  of  circumference as do the
  394.            AutoLisp-callable functions.
  395.  
  396.                                 HLS
  397.  
  398.         void rgb_hls(ads_real r, ads_real g, ads_real b,
  399.                      ads_real *h, ads_real *l, ads_real *s)
  400.            Converts r, g, b (0 to 1) to h (0 to 360), l (0 to 1),  and
  401.            s  (0  to  1).  Note that rgb_hls() returns hue in terms of
  402.            degrees, not as a  fraction  of  circumference  as  do  the
  403.            AutoLisp-callable functions.
  404.  
  405.         void hls_rgb(ads_real h, ads_real l, ads_real s,
  406.                      ads_real *r, ads_real *g, ads_real *b)
  407.            Converts  h (0 to 360), l (0 to 1), and s (0 to 1) to r, g,
  408.            b (0 to 1).  Note that rgb_hls() expects hue  in  terms  of
  409.            degrees,  not  as  a  fraction  of  circumference as do the
  410.            AutoLisp-callable functions.
  411.  
  412.                                 CNS
  413.  
  414.         void rgb_cns(ads_real r, ads_real g, ads_real b, char *cnstr)
  415.            Edits  a  zero-terminated  CNS  description  of  the colour
  416.            represented by r, g, and b (0 to 1), into the string cnstr.
  417.            The  maximum  length of the edited string is 36 characters,
  418.            so a buffer of at least 37 characters  should  be  supplied
  419.            for  cnstr.   If  the lightness of the colour is closest to
  420.            the CNS nomenclature for the default  lightness  stored  in
  421.            the  scaled  integer  variable  defcnslit (initially 10000,
  422.            representing 1),  no  intensity  is  edited.   The  default
  423.            saturation of "vivid" is not edited.
  424.  
  425.         Boolean cns_rgb(char *cns, ads_real *r, ads_real *g, ads_real *b)
  426.            Scans  a CNS specification in the string cns and stores RGB
  427.            intensities in r, g, and b which range from 0 to 1.  If  no
  428.            lightness  is  specified, the lightness (as defined for the
  429.            HSV routines) in the  scaled  integer  defcnslit  is  used.
  430.            This  value  is  initially  set  to  10000  for  a  default
  431.            intensity of very light (maximum).  The function returns  1
  432.            if  the  specification  is  valid and 0 if an incorrect CNS
  433.            specification is supplied,  in  which  case  the  character
  434.            pointer  cnserr  will  point to an error message describing
  435.            the problem.
  436.  
  437.         BIBLIOGRAPHY
  438.         ============
  439.  
  440.            Fundamentals of Interactive Computer Graphics
  441.               by J. D. Foley and A. van Dam, Reading Massachusetts:
  442.               Addison-Wesley, 1984.
  443.  
  444.            Measuring Colour
  445.               by R. W. G. Hunt, West Sussex England: Ellis Horwood
  446.               Ltd., 1987.  (Distributed by John Wiley & Sons).
  447.  
  448.            A New Color-Naming System for Graphics Languages
  449.               by Toby Berk, Lee Brownston, and Arie  Kaufman,  Florida
  450.               International  University,  IEEE  Computer  Graphics and
  451.               Applications, May 1982, Page 37.
  452.  
  453. */
  454.  
  455.  
  456. #include <stdlib.h>
  457. #include <stdio.h>
  458. #include <iostream.h>
  459. #include <string.h>
  460. #include <ctype.h>
  461. #include <math.h>
  462. #include "rxdefs.h"
  463. #include "adslib.h"
  464.  
  465.  
  466. #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
  467.  
  468.  
  469. /* ADS Function Table structure */
  470. typedef struct {
  471.     char    *name;
  472.     void    (*fptr)();
  473. } ftblent;
  474.  
  475. int funcLoad   (void);
  476. int funcUnload (void);
  477. int doFun      (void);
  478.  
  479.  
  480. extern "C" {                         
  481. AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg,void * pkt);
  482. }
  483.  
  484.  
  485. /* Special assertion handler for ADS applications. */
  486.  
  487. #ifndef NDEBUG
  488. #define assert(ex) {if (!(ex)){ads_printf( \
  489.                     /*MSG1*/"COLEXT: Assertion (%s) failed: file \"%s\", \
  490.                     line %d\n", /*MSG0*/" ex ",__FILE__,__LINE__); \
  491.                     ads_abort(/*MSG2*/"Assertion failed.");}}
  492. #else
  493. #define assert(ex)
  494. #endif
  495.  
  496. /*  Data types 
  497. */
  498. typedef enum {False = 0, True = 1} Boolean;
  499. #define V        (void)
  500.  
  501. /* Set point variable from three co-ordinates
  502. */
  503. #define Spoint(pt, x, y, z)  pt[X] = (x);  pt[Y] = (y);  pt[Z] = (z)
  504.  
  505. /* Copy point  
  506. */
  507. #define Cpoint(d, s)   d[X] = s[X];  d[Y] = s[Y];  d[Z] = s[Z]
  508.  
  509. /* Utility definition to get an  array's  element  count  (at  compile
  510.    time).   For  example:  
  511.  
  512.        int  arr[] = {1,2,3,4,5};
  513.        ... 
  514.        printf("%d", ELEMENTS(arr));
  515.  
  516.    would print a five.  ELEMENTS("abc") can also be used to  tell  how
  517.    many  bytes are in a string constant INCLUDING THE TRAILING NULL. 
  518. */
  519. #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
  520.  
  521. /* Utility definitions 
  522. */
  523. #ifdef abs
  524. #undef abs
  525. #endif
  526. #define abs(x)      ((x)<0 ? -(x) : (x))
  527. #ifdef min
  528. #undef  min
  529. #endif
  530. #define min(a,b)    ((a)<(b) ? (a) : (b))
  531. #ifdef max
  532. #undef  max
  533. #endif
  534. #define max(a,b)    ((a)>(b) ? (a) : (b))
  535.  
  536. #ifndef M_E
  537. #define M_E     2.7182818284590452354
  538. #endif
  539.  
  540. #define Tbit(x)  (tok & (1L << ((int) (x))))  /* Test token bit set */
  541. #define Tb(x)    (1L << ((int) (x)))  /* Obtain bit to test */
  542.  
  543. /* AutoCAD standard color palette */
  544.  
  545. #define         BLACK           0
  546. #define         RED             1
  547. #define         YELLOW          2
  548. #define         GREEN           3
  549. #define         CYAN            4
  550. #define         BLUE            5
  551. #define         MAGENTA         6
  552. #define         WHITE           7
  553.  
  554. #define         SAT             1.0
  555.  
  556. struct r_g_b {                        /* RGB colour description */
  557.         ads_real red, green, blue;
  558. };
  559.  
  560. /*  Colour naming system vocabulary definition.  The vocabulary
  561.     is defined in this somewhat unusal fashion to facilitate
  562.     translation to languages other than English. */
  563.  
  564. typedef enum {
  565.         /* Chromatic colours */
  566.         Red, Orange, Brown, Yellow, Green, Blue, Purple,
  567.  
  568.         /* "ish" forms of chromatic colours */
  569.         Reddish, Orangish, Brownish, Yellowish, Greenish, Bluish, Purplish,
  570.  
  571.         /* Achromatic names */
  572.         Gray, Black, White,
  573.  
  574.         /* Lightness specifications */
  575.         Very, Dark, Medium, Light,
  576.  
  577.         /* Saturation specifications */
  578.         Grayish, Moderate, Strong, Vivid,
  579.  
  580.         /* Punctuation */
  581.         Hyphen, Period, Huh
  582.        } colourvocab;
  583.  
  584. static struct {
  585.         char *cname;
  586.         colourvocab ccode;
  587. } cvocab[] = {
  588.         {/*MSG3*/"red", Red},
  589.         {/*MSG4*/"orange", Orange},
  590.         {/*MSG5*/"brown", Brown},
  591.         {/*MSG6*/"yellow", Yellow},
  592.         {/*MSG7*/"green", Green},
  593.         {/*MSG8*/"blue", Blue},
  594.         {/*MSG9*/"purple", Purple},
  595.  
  596.         {/*MSG10*/"reddish", Reddish},
  597.         {/*MSG11*/"orangish", Orangish},
  598.         {/*MSG12*/"brownish", Brownish},
  599.         {/*MSG13*/"yellowish", Yellowish},
  600.         {/*MSG14*/"greenish", Greenish},
  601.         {/*MSG15*/"bluish", Bluish},
  602.         {/*MSG16*/"purplish", Purplish},
  603.  
  604.         {/*MSG17*/"gray", Gray},
  605.         {/*MSG18*/"grey", Gray},
  606.         {/*MSG19*/"black", Black},
  607.         {/*MSG20*/"white", White},
  608.  
  609.         {/*MSG21*/"very", Very},
  610.         {/*MSG22*/"dark", Dark},
  611.         {/*MSG23*/"medium", Medium},
  612.         {/*MSG24*/"light", Light},
  613.  
  614.         {/*MSG25*/"grayish", Grayish},
  615.         {/*MSG26*/"greyish", Grayish},
  616.         {/*MSG27*/"moderate", Moderate},
  617.         {/*MSG28*/"strong", Strong},
  618.         {/*MSG29*/"vivid", Vivid}
  619.        };
  620.  
  621. /* Table mapping generic hues to HSV hue indices. */
  622.  
  623. static struct {
  624.         long cbit;
  625.         int chue;
  626. } colhue[] = {
  627.         {Tb(Red),      0},            /* red */
  628.         {Tb(Orange),  30},            /* orange */
  629.         {Tb(Brown),  -30},            /* brown */
  630.         {Tb(Yellow),  60},            /* yellow */
  631.         {Tb(Green),  120},            /* green */
  632.         {Tb(Blue),   240},            /* blue */
  633.         {Tb(Purple), 300},            /* purple */
  634.         {0L,         360}             /* red (other incarnation) */
  635.        };
  636.  
  637. /* Table mapping secondary hues to HSV hue indices. */
  638.  
  639. static struct {
  640.         long cbit;
  641.         int chue;
  642. } ishhue[] = {
  643.         {Tb(Reddish),      0},        /* reddish */
  644.         {Tb(Orangish),    30},        /* orangish */
  645.         {Tb(Brownish),   -30},        /* brownish */
  646.         {Tb(Yellowish),   60},        /* yellowish */
  647.         {Tb(Greenish),   120},        /* greenish */
  648.         {Tb(Bluish),     240},        /* bluish */
  649.         {Tb(Purplish),   300},        /* purplish */
  650.         {0L,             360}         /* reddish (other incarnation) */
  651.        };
  652.  
  653. #define MAXTK    10                   /* Maximum tokens in specification */
  654. #define MAXTKS   20                   /* Longest token in characters */
  655.  
  656. #define BROWNLIGHT  3                 /* Brown lightness:  Medium */
  657. #define BROWNSAT    3                 /* Brown saturation: Strong */
  658.  
  659. /* Modal variables  */
  660.  
  661. static int defcnslit = 10000;         /* Default lightness if none specified */
  662. static int gamut = 256;               /* Colour gamut available */
  663.  
  664. /*  Local variables  */
  665.  
  666. static char *cnserr = NULL;           /* Error message string */
  667. static char cnserb[80];               /* Error message edit buffer */
  668. static char tokenb[MAXTKS];           /* Token buffer */
  669.  
  670. /*  Forward functions  */
  671.  
  672. static void   hsv_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  673. static void   rgb_hsv _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  674. static void   rgb_hls _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  675. static ads_real hlsval _((ads_real, ads_real, ads_real));
  676. static void   hls_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  677. static void   rgb_yiq _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  678. static void   yiq_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  679. static void   rgb_cmy _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  680. static void   ctemp_rgb _((ads_real, ads_real *,ads_real *,ads_real *));
  681. #ifdef NEEDED
  682. static void   cmy_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  683. #endif
  684. static colourvocab token _((char **));
  685. static Boolean cns_rgb _((char *, ads_real *, ads_real *, ads_real *));
  686. static char    *cixname _((colourvocab));
  687. static void    rgb_cns _((ads_real, ads_real, ads_real, char *));
  688. static void    acadrgb _((int, struct r_g_b *));
  689. static int     rgbacad _((ads_real, ads_real, ads_real));
  690. static void    retrgb _((Boolean, ads_real, ads_real, ads_real));
  691. static Boolean triple _((ads_real *, Boolean));
  692. static void    cmy _((Boolean));
  693. static void    cns _((Boolean));
  694. static void    cnser _((void));
  695. static void    ctemp _((Boolean));
  696. static void    hls _((Boolean));
  697. static void    hsv _((Boolean));
  698. static void    rgb _((Boolean));
  699. static void    yiq _((Boolean));
  700. static void    cmyac _((void));
  701. static void    ctempac _((void));
  702. static void    yiqac _((void));
  703. static void    hsvac _((void));
  704. static void    rgbac _((void));
  705. static void    hlsac _((void));
  706. static void    cnsac _((void));
  707. static void    cmyrgb _((void));
  708. static void    ctemprgb _((void));
  709. static void    yiqrgb _((void));
  710. static void    hsvrgb _((void));
  711. static void    hlsrgb _((void));
  712. static void    cnsrgb _((void));
  713. static Boolean acadcol _((struct r_g_b *));
  714. static void    torgb _((void));
  715. static void    tocmy _((void));
  716. static void    toyiq _((void));
  717. static void    tohsv _((void));
  718. static void    tohls _((void));
  719. static void    tocns _((void));
  720. static void    colset _((void));
  721.  
  722. /*  Colour system to AutoCAD colour functions. */
  723.  
  724. static void cmyac()   { cmy(True);   }
  725. static void ctempac() { ctemp(True); }
  726. static void yiqac()   { yiq(True);   }
  727. static void hsvac()   { hsv(True);   }
  728. static void rgbac()   { rgb(True);   }
  729. static void hlsac()   { hls(True);   }
  730. static void cnsac()   { cns(True);   }
  731.  
  732. /*  Colour system to RGB functions.  */
  733.  
  734. static void cmyrgb()   { cmy(False);   }
  735. static void ctemprgb() { ctemp(False); }
  736. static void yiqrgb()   { yiq(False);   }
  737. static void hsvrgb()   { hsv(False);   }
  738. static void hlsrgb()   { hls(False);   }
  739. static void cnsrgb()   { cns(False);   }
  740.  
  741.  
  742. /*  Command definition and dispatch table.  */
  743.  
  744. ftblent exfun[] = {
  745.  
  746. /*        Name         Function  */
  747.  
  748. /* External colour system to AutoCAD colour functions */
  749.  
  750. {/*MSG0*/"CMY",       cmyac},
  751. {/*MSG0*/"CNS",       cnsac},
  752. {/*MSG0*/"CTEMP",     ctempac},
  753. {/*MSG0*/"HLS",       hlsac},
  754. {/*MSG0*/"HSV",       hsvac},
  755. {/*MSG0*/"RGB",       rgbac},
  756. {/*MSG0*/"YIQ",       yiqac},
  757.  
  758. /* External colour system to RGB functions */
  759.  
  760. {/*MSG0*/"CMY-RGB",   cmyrgb},
  761. {/*MSG0*/"CNS-RGB",   cnsrgb},
  762. {/*MSG0*/"CTEMP-RGB", ctemprgb},
  763. {/*MSG0*/"HLS-RGB",   hlsrgb},
  764. {/*MSG0*/"HSV-RGB",   hsvrgb},
  765. {/*MSG0*/"YIQ-RGB",   yiqrgb},
  766.  
  767. /* AutoCAD colour index to external colour system functions */
  768.  
  769. {/*MSG0*/"TO-RGB",    torgb},
  770. {/*MSG0*/"TO-CMY",    tocmy},
  771. {/*MSG0*/"TO-YIQ",    toyiq},
  772. {/*MSG0*/"TO-HSV",    tohsv},
  773. {/*MSG0*/"TO-HLS",    tohls},
  774. {/*MSG0*/"TO-CNS",    tocns},
  775.  
  776. /* Control and utility functions */
  777.  
  778. {/*MSG0*/"CNSERR",    cnser},
  779. {/*MSG0*/"COLSET",    colset}
  780. };
  781.  
  782.  
  783. /******************************************************************************/
  784. /*.doc funcLoad(internal) */
  785. /*+
  786.     This function is called to define all function names in the ADS
  787.     function table.  Each named function will be callable from lisp or
  788.     invokable from another ADS application.
  789. -*/
  790. /******************************************************************************/
  791. int
  792. /*FCN*/funcLoad()
  793. {
  794.     int i;
  795.  
  796.     for (i = 0; i < ELEMENTS(exfun); i++) {
  797.         if (!ads_defun(exfun[i].name, i))
  798.             return RTERROR;
  799.     }
  800.  
  801.     return RTNORM;
  802. }
  803.  
  804.  
  805. /******************************************************************************/
  806. /*.doc funclUnload(internal) */
  807. /*+
  808.     This function is called to undefine all function names in the ADS
  809.     function table.  Each named function will be removed from the
  810.     AutoLISP hash table.
  811. -*/
  812. /******************************************************************************/
  813. int
  814. /*FCN*/funcUnload()
  815. {
  816.     int i;
  817.  
  818.     /* Undefine each function we defined */
  819.  
  820.     for (i = 0; i < ELEMENTS(exfun); i++) {
  821.         ads_undef(exfun[i].name,i);
  822.     }
  823.  
  824.     return RTNORM;
  825. }
  826.  
  827.  
  828. /******************************************************************************/
  829. /*.doc doFun(internal) */
  830. /*+
  831.     This function is called to invoke the function which has the
  832.     registerd function code that is obtained from  ads_getfuncode.  The
  833.     function will return RTERROR if the function code is invalid, or
  834.     RSERR if the invoked function fails to return RTNORM.  The value
  835.     RSRSLT will be returned if the function code is valid and the
  836.     invoked subroutine returns RTNORM.
  837. -*/
  838. /******************************************************************************/
  839. int
  840. /*FCN*/doFun()
  841. {
  842.     int    val;
  843.  
  844.     ads_retvoid();
  845.         
  846.     if ((val = ads_getfuncode()) < 0 || val > ELEMENTS(exfun))
  847.         return RTERROR;
  848.  
  849.     (*exfun[val].fptr)();
  850.  
  851.     return RTNORM;
  852. }
  853.  
  854.  
  855. AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* ptr)
  856. {
  857.  
  858.     if (ptr != NULL) {
  859.         // We have been handed some kind of object
  860.         // but we aren't going to do anything with it.
  861.     }
  862.  
  863.     switch(msg) {
  864.     case AcRx::kInitAppMsg:
  865.         break;
  866.         case AcRx::kInvkSubrMsg:
  867.             doFun();
  868.             break;
  869.         case AcRx::kLoadADSMsg:
  870.             funcLoad();
  871.             break;
  872.         case AcRx::kUnloadADSMsg:
  873.             funcUnload();
  874.             ads_printf(/*MSG2*/"Unloading.\n");
  875.             break;
  876.     case AcRx::kUnloadAppMsg:
  877.         default:
  878.         break;
  879.     }
  880.     return AcRx::kRetOK;
  881. }
  882.  
  883.  
  884. /*      ***************************************************
  885.         **                                               **
  886.         **       Colour Interconversion Functions        **
  887.         **                                               **
  888.         ***************************************************
  889. */
  890.  
  891. /*  HSV_RGB  --  Convert HSV colour specification to RGB  intensities.
  892.                  Hue is specified as a  real  value  from  0  to  360,
  893.                  Saturation  and  Intensity as reals from 0 to 1.  The
  894.                  RGB components are returned as reals from 0 to 1.      */
  895.  
  896. static void hsv_rgb(ads_real h, ads_real s, ads_real v,
  897.         ads_real *r, ads_real *g, ads_real *b)
  898. {
  899.     int i;
  900.     ads_real f, p, q, t;
  901.  
  902.     if (s == 0) {
  903.         *r = *g = *b = v;
  904.     } else {
  905.         if (h == 360.0)
  906.             h = 0;
  907.         h /= 60.0;
  908.  
  909.         i = (int)h;
  910.         f = h - i;
  911.         p = v * (1.0 - s);
  912.         q = v * (1.0 - (s * f));
  913.         t = v * (1.0 - (s * (1.0 - f)));
  914.         // assert(i >= 0 && i <= 5);
  915.         switch (i) {
  916.  
  917.         case 0:
  918.             *r = v;
  919.             *g = t;
  920.             *b = p;
  921.             break;
  922.  
  923.         case 1:
  924.             *r = q;
  925.             *g = v;
  926.             *b = p;
  927.             break;
  928.  
  929.         case 2:
  930.             *r = p;
  931.             *g = v;
  932.             *b = t;
  933.             break;
  934.  
  935.         case 3:
  936.             *r = p;
  937.             *g = q;
  938.             *b = v;
  939.             break;
  940.  
  941.         case 4:
  942.             *r = t;
  943.             *g = p;
  944.             *b = v;
  945.             break;
  946.  
  947.         case 5:
  948.             *r = v;
  949.             *g = p;
  950.             *b = q;
  951.             break;
  952.         }
  953.     }
  954. }
  955.  
  956. /*  RGB_HSV  --  Map R, G, B intensities in the range from 0 to 1 into
  957.                  Hue, Saturation,  and  Value:  Hue  from  0  to  360,
  958.                  Saturation  from  0  to  1,  and  Value  from 0 to 1.
  959.                  Special case: if Saturation is 0 (it's a  grey  scale
  960.                  tone), Hue is undefined and is returned as -1.
  961.  
  962.                  This follows Foley & van Dam, section 17.4.4.  */
  963.  
  964. static void rgb_hsv(ads_real r, ads_real g, ads_real b, 
  965.         ads_real *h, ads_real *s, ads_real *v)
  966. {
  967.     ads_real imax = max(r, max(g, b)),
  968.              imin = min(r, min(g, b)),
  969.              rc, gc, bc;
  970.  
  971.     *v = imax;
  972.     if (imax != 0)
  973.         *s = (imax - imin) / imax;
  974.     else
  975.         *s = 0;
  976.  
  977.     if (*s == 0) {
  978.         *h = -1;
  979.     } else {
  980.         rc = (imax - r) / (imax - imin);
  981.         gc = (imax - g) / (imax - imin);
  982.         bc = (imax - b) / (imax - imin);
  983.         if (r == imax)
  984.             *h = bc - gc;
  985.         else if (g == imax)
  986.             *h = 2.0 + rc - bc;
  987.         else
  988.             *h = 4.0 + gc - rc;
  989.         *h *= 60.0;
  990.         if (*h < 0.0)
  991.             *h += 360.0;
  992.     }
  993. }
  994.  
  995. /*  RGB_HLS  --  Map R, G, B intensities in the range from 0 to 1 into
  996.                  Hue, Lightness, and Saturation: Hue from  0  to  360,
  997.                  Lightness  from  0  to 1, and Saturation from 0 to 1.
  998.                  Special case: if Saturation is 0 (it's a  grey  scale
  999.                  tone), Hue is undefined and is returned as -1.
  1000.  
  1001.                  This follows Foley & van Dam, section 17.4.5.  */
  1002.  
  1003. static void rgb_hls(ads_real r, ads_real g, ads_real b, 
  1004.         ads_real *h, ads_real *l, ads_real *s)
  1005. {
  1006.     ads_real imax = max(r, max(g, b)),
  1007.              imin = min(r, min(g, b)),
  1008.              rc, gc, bc;
  1009.  
  1010.     *l = (imax + imin) / 2;
  1011.  
  1012.     if (imax == imin) {
  1013.         *s = 0;
  1014.         *h = -1;
  1015.     } else {
  1016.         if (*l <= 0.5)
  1017.             *s = (imax - imin) / (imax + imin);
  1018.         else
  1019.             *s = (imax - imin) /
  1020.                  (2.0 - imax - imin);
  1021.  
  1022.         rc = (imax - r) / (imax - imin);
  1023.         gc = (imax - g) / (imax - imin);
  1024.         bc = (imax - b) / (imax - imin);
  1025.         if (r == imax)
  1026.             *h = bc - gc;
  1027.         else if (g == imax)
  1028.             *h = 2.0 + rc - bc;
  1029.         else
  1030.             *h = 4.0 + gc - rc;
  1031.         *h *= 60.0;
  1032.         if (*h < 0)
  1033.             *h += 360.0;
  1034.     }
  1035. }
  1036.  
  1037. /*  HLS_RGB  --  Convert HLS colour specification to RGB  intensities.
  1038.                  Hue  is  specified  as  a  real  value from 0 to 360;
  1039.                  Lightness and Saturation as reals from 0 to  1.   The
  1040.                  RGB components are returned as reals from 0 to 1.      */
  1041.  
  1042. static ads_real hlsval(ads_real n1, ads_real n2, ads_real hue)
  1043. {
  1044.     if (hue > 360.0)
  1045.         hue -= 360.0;
  1046.     else if (hue < 0.0)
  1047.         hue += 360.0;
  1048.     if (hue < 60.0) {
  1049.         return n1 + ((n2 - n1) * hue) / 60.0;
  1050.     } else if (hue < 180.0) {
  1051.         return n2;
  1052.     } else if (hue < 240.0) {
  1053.         return n1 + ((n2 - n1) * (240.0 - hue)) / 60.0;
  1054.     } else {
  1055.         return n1;
  1056.     }
  1057. }
  1058.  
  1059. static void hls_rgb(ads_real h, ads_real l, ads_real s, 
  1060.         ads_real *r, ads_real *g, ads_real *b)
  1061. {
  1062.     ads_real m1, m2;
  1063.  
  1064.     if (l <= 0.5)
  1065.         m2 = l * (1.0 + s);
  1066.     else
  1067.         m2 = l + s - (l * s);
  1068.     m1 = 2 * l - m2;
  1069.  
  1070.     if (s == 0) {
  1071.         *r = *g = *b = l;
  1072.     } else {
  1073.         *r = hlsval(m1, m2, h + 120.0);
  1074.         *g = hlsval(m1, m2, h);
  1075.         *b = hlsval(m1, m2, h - 120.0);
  1076.     }
  1077. }
  1078.  
  1079. /*  RGB_YIQ  --  Convert RGB colour specification, R, G, B ranging
  1080.                  from 0 to 1, to Y, I, Q colour specification.
  1081.  
  1082.                  |Y|   |0.30  0.59  0.11|   |R|
  1083.                  |I| = |0.60 -0.28 -0.32| . |G|
  1084.                  |Q|   |0.21 -0.52  0.31|   |B|
  1085. */
  1086.  
  1087. static void rgb_yiq(ads_real r, ads_real g, ads_real b, 
  1088.         ads_real *y, ads_real *i, ads_real *q)
  1089. {
  1090.     ads_real ay = (r * 0.30 + g *  0.59 + b *  0.11),
  1091.              ai = (r * 0.60 + g * -0.28 + b * -0.32),
  1092.              aq = (r * 0.21 + g * -0.52 + b *  0.31);
  1093.  
  1094.     *y = ay;
  1095.     if (ay == 1.0) {                  /* Prevent round-off on grey scale */
  1096.         ai = aq = 0.0;
  1097.     }
  1098.     *i = ai;
  1099.     *q = aq;
  1100. }
  1101.  
  1102. /*  YIQ_RGB  --  Convert YIQ colour specification, Y, I,  Q  given  as
  1103.                  reals,  Y  from  0  to  1, I from -0.6 to 0.6, Q from
  1104.                  -0.52 to 0.52, to R, G, B intensities  in  the  range
  1105.                  from  0 to 1.  The matrix below is the inverse of the
  1106.                  RGB_YIQ matrix above.
  1107.  
  1108.                  |R|   |1.00  0.948  0.624|   |Y|
  1109.                  |G| = |1.00 -0.276 -0.640| . |I|
  1110.                  |B|   |1.00 -1.105  1.730|   |Q|
  1111. */
  1112.  
  1113. static void yiq_rgb(ads_real y, ads_real i, ads_real q, 
  1114.         ads_real *r, ads_real *g, ads_real *b)
  1115. {
  1116.     ads_real ar = (y + i *   0.948 + q *  0.624),
  1117.              ag = (y + i *  -0.276 + q * -0.640),
  1118.              ab = (y + i *  -1.105 + q *  1.730);
  1119.  
  1120.     *r = max(0, min(1.0, ar));
  1121.     *g = max(0, min(1.0, ag));
  1122.     *b = max(0, min(1.0, ab));
  1123. }
  1124.  
  1125. /*  RGB_CMY  --  Convert RGB colour specification,  R,  G,  B  ranging
  1126.                  from  0  to  1, to C, M, Y colour specification, also
  1127.                  ranging from 0 to 1.
  1128.  
  1129.                  |C|   |1|   |R|
  1130.                  |M| = |1| - |G|
  1131.                  |Y|   |1|   |B|
  1132. */
  1133.  
  1134. static void rgb_cmy(ads_real r, ads_real g, ads_real b, 
  1135.         ads_real *c, ads_real *m, ads_real *y)
  1136. {
  1137.     *c = 1.0 - r;
  1138.     *m = 1.0 - g;
  1139.     *y = 1.0 - b;
  1140. }
  1141.  
  1142. #ifdef NEEDED
  1143.  
  1144. /*  CMY_RGB  --  Convert CMY colour specification,  C,  M,  Y  ranging
  1145.                  from  0  to  1, to R, G, B colour specification, also
  1146.                  ranging from 0 to 1.
  1147.  
  1148.                  |R|   |1|   |C|
  1149.                  |G| = |1| - |M|
  1150.                  |B|   |1|   |Y|
  1151. */
  1152.  
  1153. static void cmy_rgb(ads_real c, ads_real m, ads_real y, 
  1154.         ads_real *r, ads_real *g, ads_real *b)
  1155. {
  1156.     *r = 1.0 - c;
  1157.     *g = 1.0 - m;
  1158.     *b = 1.0 - y;
  1159. }
  1160. #endif
  1161.  
  1162. /*  CTEMP_RGB  --  Calculate the relative R, G, and B components for a
  1163.                    black body emitting light at a  given  temperature.
  1164.                    The  Planck  radiation  equation is solved directly
  1165.                    for the R, G, and B wavelengths defined for the CIE
  1166.                    1931  Standard  Colorimetric  Observer.  The colour
  1167.                    temperature is specified in degrees Kelvin. */
  1168.  
  1169. static void ctemp_rgb(double temp, double *r, double *g, double *b)
  1170. {
  1171.     double c1 = 3.74183e10,
  1172.            c2 = 14388.0,
  1173.            er, eg, eb, es;
  1174.  
  1175. /* Lambda is the wavelength in microns: 5500 angstroms is 0.55 microns. */
  1176.  
  1177. #define Planck(lambda)  ((c1 * pow((double) lambda, -5.0)) /  \
  1178.                          (pow(M_E, c2 / (lambda * temp)) - 1))
  1179.  
  1180.     er = Planck(0.7000);
  1181.     eg = Planck(0.5461);
  1182.     eb = Planck(0.4358);
  1183. #undef Planck
  1184.  
  1185.     es = 1.0 / max(er, max(eg, eb));
  1186.  
  1187.     *r = er * es;
  1188.     *g = eg * es;
  1189.     *b = eb * es;
  1190. }
  1191.  
  1192. /*  TOKEN  --  Scan next token from the CNS string and update the
  1193.                scan pointer.  */
  1194.  
  1195. static colourvocab token(char **icp)
  1196. {
  1197.     char ch;
  1198.     char *cp = *icp, *tch;
  1199.     int i, t = 0;
  1200.  
  1201.     /* Ignore leading space */
  1202.  
  1203.     while (True) {
  1204.         ch = *cp++;
  1205.         if (!isspace(ch))
  1206.             break;
  1207.     }
  1208.  
  1209.     if (ch == EOS)
  1210.         return Period;
  1211.  
  1212.     if (ch == '-') {
  1213.         *icp = cp;
  1214.         return Hyphen;
  1215.     }
  1216.  
  1217.     tch = cp - 1;                     /* Start of token pointer */
  1218.     if (!isalpha(ch)) {
  1219.         *cp = EOS;
  1220.         *icp = tch;
  1221.         return Huh;
  1222.     }
  1223.  
  1224.     while (isalpha(ch)) {
  1225.         if (isupper(ch))
  1226.             ch = tolower(ch);
  1227.         if (t < ((sizeof tokenb) - 2))
  1228.             tokenb[t++] = ch;
  1229.         ch = *cp++;
  1230.     }
  1231.     tokenb[t] = EOS;
  1232.     *icp = cp - 1;
  1233.  
  1234.     for (i = 0; i < ELEMENTS(cvocab); i++) {
  1235.         if (strcmp(tokenb, cvocab[i].cname) == 0) {
  1236.             return cvocab[i].ccode;
  1237.         }
  1238.     }
  1239.     **icp = EOS;
  1240.     *icp = tch;
  1241.     return Huh;
  1242. }
  1243.  
  1244. /*  CNS_RGB  --  Convert a CNS string to RGB intensities scaled from 0
  1245.                  to 1.  If an invalid specification is made,  0
  1246.                  is returned and an error message is pointed to by the
  1247.                  global character pointer  cnserr.   Otherwise,  1  is
  1248.                  returned.  */
  1249.  
  1250. static Boolean cns_rgb(char *cns, ads_real *r, ads_real *g, ads_real *b)
  1251. {
  1252.     int i, j, k = 0, lightness, saturation;
  1253.     long tok = 0L, hue;
  1254.     colourvocab t;
  1255.     static char conflite[] = /*MSG31*/"Conflicting lightness specification.";
  1256.     /* Grey scale table */
  1257.     static int greyscale[] = {50, 17, 33, 50, 67, 83};
  1258.     /* Saturation percentage table */
  1259.     static int satab[] = {10000, 2500, 5000, 7500, 10000};
  1260.     /* Chromatic lightness table */
  1261.     static int litetab[] = {5000, 1300, 2500, 5000, 7500, 10000};
  1262.  
  1263.     cnserr = NULL;                    /* Initially no error in CNS string */
  1264.     j = strlen(cns);
  1265.     if (j == 0) {
  1266.         cnserr = /*MSG32*/"Void specification.";
  1267.         return False;
  1268.     }
  1269.  
  1270.     /* Scan string and parse tokens */
  1271.  
  1272.     while (True) {
  1273.         t = token(&cns);
  1274.         if (t == Huh) {
  1275.             V sprintf(cnserb, /*MSG33*/"Unrecognised symbol: `%s'.", cns);
  1276.             cnserr = cnserb;
  1277.             return False;
  1278.         }
  1279.         if (Tbit(t)) {
  1280.             V sprintf(cnserb, /*MSG34*/"Duplicate symbol: `%s'.", tokenb);
  1281.             cnserr = cnserb;
  1282.             return False;
  1283.         }
  1284.         if (t == Period)
  1285.             break;
  1286.         tok |= 1L << ((int) t);
  1287.     }
  1288.  
  1289.     /* Try to obtain lightness from specification */
  1290.  
  1291.     if (tok & (Tb(Very) | Tb(Dark) | Tb(Medium) | Tb(Light))) {
  1292.         if (Tbit(Medium)) {
  1293.             if (Tbit(Very)) {
  1294.                 cnserr = /*MSG35*/"Very used with Medium.";
  1295.                 return False;
  1296.             }
  1297.             if (Tbit(Light) || Tbit(Dark)) {
  1298.                 cnserr = conflite;
  1299.                 return False;
  1300.             }
  1301.             lightness = 3;
  1302.         } else if (Tbit(Dark)) {
  1303.             lightness = Tbit(Very) ? 1 : 2;
  1304.             if (Tbit(Light)) {
  1305.                 cnserr = conflite;
  1306.                 return False;
  1307.             }
  1308.         } else if (Tbit(Light)) {
  1309.             lightness = Tbit(Very) ? 5 : 4;
  1310.         } else {
  1311.             cnserr = /*MSG36*/"Very used without Light or Dark.";
  1312.             return False;
  1313.         }
  1314.     } else {
  1315.         lightness = 0;
  1316.     }
  1317.  
  1318.     /* Test for achromatic colour specification. */
  1319.  
  1320.     i = !!(Tbit(Black)) + !!(Tbit(Gray)) + !!(Tbit(White));
  1321.     if (i > 0) {
  1322.  
  1323.         /* Test for conflicting specification of more than
  1324.            one achromatic colour. */
  1325.  
  1326.         if (i != 1) {
  1327.             cnserr = /*MSG37*/"Conflicting black/gray/white specification.";
  1328.             return False;
  1329.         }
  1330.  
  1331.         /* Test for specification of chromatic colour with
  1332.            achromatic colour. */
  1333.  
  1334.         if (tok & (Tb(Red) | Tb(Orange) | Tb(Brown) | Tb(Yellow) |
  1335.                    Tb(Green) | Tb(Blue) | Tb(Purple))) {
  1336.             cnserr = /*MSG38*/"Chromatic and achromatic shade mixed.";
  1337.             return False;
  1338.         }
  1339.  
  1340.         /* Test for specification of chromatic colour ish form with
  1341.            achromatic colour. */
  1342.  
  1343.         if (tok & (Tb(Reddish) | Tb(Orangish) |
  1344.                    Tb(Brownish) | Tb(Yellowish) |
  1345.                    Tb(Greenish) | Tb(Bluish) | Tb(Purplish) |
  1346.                    Tb(Hyphen))) {
  1347.             cnserr = /*MSG39*/"Chromatic modifier and achromatic shade mixed.";
  1348.             return False;
  1349.         }
  1350.  
  1351.         /* Test for saturation specification with achromatic shade. */
  1352.  
  1353.         if (tok & (Tb(Grayish) | Tb(Moderate) | Tb(Strong) | Tb(Vivid))) {
  1354.             cnserr = /*MSG40*/"Saturation specified with achromatic shade.";
  1355.             return False;
  1356.         }
  1357.  
  1358.         /* Test for lightness specified with White or Black. */
  1359.  
  1360.         if (Tbit(White) || Tbit(Black)) {
  1361.             if (tok & (Tb(Very) | Tb(Dark) | Tb(Medium) | Tb(Light))) {
  1362.                 cnserr = /*MSG41*/"Lightness specified with black or white.";
  1363.                 return False;
  1364.             }
  1365.             if (Tbit(White)) {
  1366.                 *r = *g = *b = 1.0;   /* White */
  1367.             } else {
  1368.                 *r = *g = *b = 0;     /* Black */
  1369.             }
  1370.             return True;
  1371.         }
  1372.  
  1373.         /* Calculate grey scale value from lightness specification. */
  1374.  
  1375.         *r = *g = *b = greyscale[lightness] / 100.0;
  1376.         return True;
  1377.     }
  1378.  
  1379.     /* It isn't a grey scale, so it must be a chromatic colour
  1380.        specification.  Before we tear into the hue, let's try and
  1381.        determine the saturation. */
  1382.  
  1383.     i = (!!Tbit(Grayish)) + (!!Tbit(Moderate)) +
  1384.         (!!Tbit(Strong)) + (!!Tbit(Vivid));
  1385.     if (i > 0) {
  1386.         if (i > 1) {
  1387.             cnserr = /*MSG42*/"Conflicting saturation specification.";
  1388.             return False;
  1389.         }
  1390.         saturation = Tbit(Grayish) ? 1 :
  1391.                      (Tbit(Moderate) ? 2 :
  1392.                       (Tbit(Strong) ? 3 : 4));
  1393.     } else {
  1394.         saturation = 0;
  1395.     }
  1396.  
  1397.     /* Count primary hue specifications. */
  1398.  
  1399.     i = (!!Tbit(Red)) + (!!Tbit(Orange)) + (!!Tbit(Brown)) +
  1400.         (!!Tbit(Yellow)) +
  1401.         (!!Tbit(Green)) + (!!Tbit(Blue)) + (!!Tbit(Purple));
  1402.  
  1403.     if (i == 0) {
  1404.         cnserr = /*MSG43*/"No hue specified.";
  1405.         return False;
  1406.     }
  1407.     if (i > 2) {
  1408.         cnserr = /*MSG44*/"More than two hues specified.";
  1409.         return False;
  1410.     }
  1411.  
  1412.     /* Count secondary hue specifications. */
  1413.  
  1414.     j = (!!Tbit(Reddish)) + (!!Tbit(Orangish)) + (!!Tbit(Brownish)) +
  1415.         (!!Tbit(Yellowish)) +
  1416.         (!!Tbit(Greenish)) + (!!Tbit(Bluish)) + (!!Tbit(Purplish));
  1417.  
  1418.     if (j > 1) {
  1419.         cnserr = /*MSG45*/"More than one secondary hue specified.";
  1420.         return False;
  1421.     }
  1422.     if (i == 2 && j > 0) {
  1423.         cnserr = /*MSG46*/"Secondary hue specified with two primary hues.";
  1424.         return False;
  1425.     }
  1426.  
  1427.     /* Obtain hue based on form of specification we've determined
  1428.        is being made.
  1429.  
  1430.        Case 1.  Pure hue specified by a single primary hue. */
  1431.  
  1432.     hue = -1;
  1433.     if (i == 1 && j == 0) {
  1434.         for (i = 0; i < ELEMENTS(colhue); i++) {
  1435.             if (tok & colhue[i].cbit) {
  1436.                 hue = abs(colhue[i].chue) * 100L;
  1437.                 /* If it's brown, impute saturation and lightness
  1438.                    if none was explicitly specified. */
  1439.                 if (colhue[i].chue < 0) {
  1440.                     if (lightness == 0)
  1441.                         lightness = BROWNLIGHT;
  1442.                     if (saturation == 0)
  1443.                         saturation = BROWNSAT;
  1444.                 }
  1445.                 break;
  1446.             }
  1447.         }
  1448.     } else if (i == 2) {
  1449.  
  1450.         /* Case 2.  Halfway hue specified by composing two adjacent
  1451.                     primary hues. */
  1452.  
  1453.         j = k = -1;
  1454.         for (i = 0; i < ELEMENTS(colhue); i++) {
  1455.             if (tok & colhue[i].cbit) {
  1456.                 if (j < 0)
  1457.                     j = i;
  1458.                 else {
  1459.                     k = i;
  1460.                     break;
  1461.                 }
  1462.             }
  1463.         }
  1464.         if ((colhue[j].chue == -colhue[k].chue) ||
  1465.             (((j + 1) != k) &&
  1466.              !(j == 0 && k == 2) && !(j == 1 && k == 3) &&
  1467.              (!(j == 0 && k == (ELEMENTS(colhue) - 2))))) {
  1468.             cnserr = /*MSG47*/"Two primary hues are not adjacent.";
  1469.             return False;
  1470.         }
  1471.  
  1472.         if (Tbit(Red) && Tbit(Purple))
  1473.             j = ELEMENTS(colhue) - 1;
  1474.  
  1475.         hue = (abs(colhue[j].chue) + abs(colhue[k].chue)) * 50L;
  1476.         /* If either is brown, impute saturation and lightness
  1477.            if none was explicitly specified. */
  1478.         if (colhue[j].chue < 0 || colhue[k].chue < 0) {
  1479.             if (lightness == 0)
  1480.                 lightness = BROWNLIGHT;
  1481.             if (saturation == 0)
  1482.                 saturation = BROWNSAT;
  1483.         }
  1484.     } else {
  1485.  
  1486.         /* Case 3.  Quarterway hue specified by one primary hue
  1487.                     and one secondary hue. */
  1488.  
  1489.         for (i = 0; i < ELEMENTS(colhue); i++) {
  1490.             if (tok & colhue[i].cbit) {
  1491.                 j = i;
  1492.                 break;
  1493.             }
  1494.         }
  1495.         for (i = 0; i < ELEMENTS(ishhue); i++) {
  1496.             if (tok & ishhue[i].cbit) {
  1497.                 k = i;
  1498.                 break;
  1499.             }
  1500.         }
  1501.         if ((colhue[j].chue == -colhue[k].chue) || (
  1502.                ((j + 1) != k) && ((j - 1) != k) &&
  1503.                !(j == 0 && k == 2) && !(j == 1 && k == 3) &&
  1504.                !(k == 0 && j == 2) && !(k == 1 && j == 3) &&
  1505.                (!(j == 0 && k == (ELEMENTS(ishhue) - 2))) &&
  1506.                (!(k == 0 && j == (ELEMENTS(ishhue) - 2)))
  1507.               )
  1508.            ) {
  1509.             cnserr = /*MSG48*/"Primary and secondary hues are not adjacent.";
  1510.             return False;
  1511.         }
  1512.  
  1513.         if (Tbit(Red) && Tbit(Purplish))
  1514.             j = ELEMENTS(colhue) - 1;
  1515.         else if (Tbit(Purple) && Tbit(Reddish))
  1516.             k = ELEMENTS(ishhue) - 1;
  1517.  
  1518.         hue = (abs(colhue[j].chue) * 3 + abs(ishhue[k].chue)) * 25L;
  1519.  
  1520.         /* If either is brown, impute saturation and lightness
  1521.            if none was explicitly specified. */
  1522.  
  1523.         if (colhue[j].chue < 0 || ishhue[k].chue < 0) {
  1524.             if (lightness == 0)
  1525.                 lightness = BROWNLIGHT;
  1526.             if (saturation == 0)
  1527.                 saturation = BROWNSAT;
  1528.         }
  1529.     }
  1530.  
  1531.     if (hue < 0) {
  1532.         cnserr = /*MSG49*/"Internal error--cannot determine hue.";
  1533.         return False;
  1534.     }
  1535.  
  1536.     if (lightness == 0)
  1537.         k = defcnslit;
  1538.     else
  1539.         k = litetab[lightness];
  1540.  
  1541.     hsv_rgb(hue / 100.0, satab[saturation] / 10000.0, k / 10000.0,
  1542.             r, g, b);
  1543.     return True;
  1544. }
  1545.  
  1546. /*  CIXNAME  --  Find name of colour vocabulary word from its index.  */
  1547.  
  1548. static char *cixname( colourvocab cx)
  1549. {
  1550.     int i;
  1551.  
  1552.     for (i = 0; i < ELEMENTS(cvocab); i++)
  1553.         if (cvocab[i].ccode == cx)
  1554.             break;
  1555.     return cvocab[i].cname;
  1556. }
  1557.  
  1558. /*  RGB_CNS  --  Find best CNS description for RGB colour expressed
  1559.                  in R, G, and B, from 0 to 1.  */
  1560.  
  1561. static void rgb_cns(ads_real r, ads_real g, ads_real b, char *cnstr)
  1562. {
  1563.     int i, j = 0, k, d, s, v;
  1564.     long lh, ld, hd;
  1565.     ads_real rh, rs, rv;
  1566.  
  1567. #define C(x)  ((char) (x))
  1568. #define CV(x) ((colourvocab) (x))
  1569.  
  1570.     /* Grey scale name table */
  1571.  
  1572.     static struct {
  1573.        int intens;
  1574.        char gname[3];
  1575.     } gtab[] = {
  1576.        {0,     {C(Black),                  0}},
  1577.        {1700,  {C(Very),  C(Dark), C(Gray)  }},
  1578.        {3300,  {C(Dark),  C(Gray),         0}},
  1579.        {5000,  {C(Gray),                   0}},
  1580.        {6700,  {C(Light), C(Gray),         0}},
  1581.        {8300,  {C(Very),  C(Light), C(Gray) }},
  1582.        {10000, {C(White),                  0}}
  1583.       };
  1584.  
  1585.     /* Hue name table */
  1586.  
  1587.     static struct {
  1588.        long huecode;
  1589.        char purename,
  1590.             ishname;
  1591.     } huetab[] = {
  1592.        {0L,     C(Red),    C(Reddish)},
  1593.        {3000L,  C(Orange), C(Orangish)},
  1594.        {6000L,  C(Yellow), C(Yellowish)},
  1595.        {12000L, C(Green),  C(Greenish)},
  1596.        {24000L, C(Blue),   C(Bluish)},
  1597.        {30000L, C(Purple), C(Purplish)},
  1598.        {36000L, C(Red),    C(Reddish)}
  1599.       };
  1600.  
  1601.     /* Chromatic lightness table */
  1602.  
  1603.     static struct {
  1604.        int intens;
  1605.        char lname[2];
  1606.     } ltab[] = {
  1607.        {1250,  {C(Very), C(Dark)  }},
  1608.        {2500,  {C(Dark),         0}},
  1609.        {5000,  {C(Medium),       0}},
  1610.        {7500,  {C(Light),        0}},
  1611.        {10000, {C(Very), C(Light) }}
  1612.       };
  1613.  
  1614.     /* Chromatic saturation table */
  1615.  
  1616.     static struct {
  1617.        int satper;
  1618.        char sname;
  1619.     } stab[] = {
  1620.        {2500,  C(Grayish)  },
  1621.        {5000,  C(Moderate) },
  1622.        {7500,  C(Strong)   },
  1623.        {10000, C(Vivid)    }
  1624.       };
  1625.  
  1626.     cnstr[0] = EOS;
  1627.  
  1628.     rgb_hsv(r, g, b, &rh, &rs, &rv);
  1629.     lh = rh * 100L;
  1630.     s = rs * 10000;
  1631.     v = rv * 10000;
  1632.  
  1633.     if (s == 0) {
  1634.  
  1635.         /* Achromatic */
  1636.  
  1637.         d = 20000;
  1638.         for (i = 0; i < ELEMENTS(gtab); i++) {
  1639.             if (abs(gtab[i].intens - v) < d) {
  1640.                 d = abs(gtab[i].intens - v);
  1641.                 j = i;
  1642.             }
  1643.         }
  1644.         for (i = 0; i < 3; i++) {
  1645.             if (gtab[j].gname[i] == 0)
  1646.                 break;
  1647.             if (strlen(cnstr))
  1648.                 V strcat(cnstr, " ");
  1649.             V strcat(cnstr, cixname(CV(gtab[j].gname[i])));
  1650.         }
  1651.     } else {
  1652.  
  1653.         /* Chromatic.  */
  1654.  
  1655.         /* Locate intensity.   If  the  closest  intensity  is  the
  1656.            default  intensity  in  DEFCNSLIT,  we  don't  edit  any
  1657.            intensity.  You can disable this by setting DEFCNSLIT to
  1658.            -1.  */
  1659.  
  1660.         d = 20000;
  1661.         for (i = 0; i < ELEMENTS(ltab); i++) {
  1662.             if (abs(ltab[i].intens - v) < d) {
  1663.                 d = abs(ltab[i].intens - v);
  1664.                 j = i;
  1665.             }
  1666.         }
  1667.         if (ltab[j].intens != defcnslit) {
  1668.             for (i = 0; i < 2; i++) {
  1669.                 if (ltab[j].lname[i] == 0)
  1670.                     break;
  1671.                 if (strlen(cnstr))
  1672.                     V strcat(cnstr, " ");
  1673.                 V strcat(cnstr, cixname(CV(ltab[j].lname[i])));
  1674.             }
  1675.         }
  1676.  
  1677.         /* Locate saturation.  If the saturation is vivid, nothing
  1678.            is edited. */
  1679.  
  1680.         d = 20000;
  1681.         for (i = 0; i < ELEMENTS(stab); i++) {
  1682.             if (abs(stab[i].satper - s) <= d) {
  1683.                 d = abs(stab[i].satper - s);
  1684.                 j = i;
  1685.             }
  1686.         }
  1687.         if (stab[j].satper != 10000) {
  1688.             if (strlen(cnstr))
  1689.                 V strcat(cnstr, " ");
  1690.             V strcat(cnstr, cixname(CV(stab[j].sname)));
  1691.         }
  1692.  
  1693.         if (strlen(cnstr))
  1694.             V strcat(cnstr, " ");
  1695.  
  1696.         /* Find closest hue name. */
  1697.  
  1698.         ld = 100000L;
  1699.         if (lh == 36000L)
  1700.             lh = 0;
  1701.         for (i = 0; i < ELEMENTS(huetab); i++) {
  1702.             if (abs(huetab[i].huecode - lh) < ld) {
  1703.                 ld = abs(huetab[i].huecode - lh);
  1704.                 j = i;
  1705.             }
  1706.         }
  1707.  
  1708.         /* Now we'll find the next hue in the direction of the
  1709.            actual hue from the specified hue. */
  1710.  
  1711.         if (lh > huetab[j].huecode) {
  1712.             if (j == (ELEMENTS(huetab) - 1))
  1713.                 k = 1;
  1714.             else
  1715.                 k = j + 1;
  1716.         } else {
  1717.             if (j == 0)
  1718.                 k = ELEMENTS(huetab) - 2;
  1719.             else
  1720.                 k = j - 1;
  1721.         }
  1722.  
  1723.         /* Next, compute the distance between the hue and the next
  1724.            neighbour in the hue's direction.  */
  1725.  
  1726.         hd = abs(huetab[j].huecode - huetab[k].huecode);
  1727.  
  1728.         /* The  form of the hue then  depends upon the relationship
  1729.            between the actual distance, D, and the total  distance,
  1730.            HD,  from the closest pure hue, J, and the next pure hue
  1731.            in the direction of the hue supplied,  K.   We  generate
  1732.            the following based upon the relationship:
  1733.  
  1734.                  D / HD          Name
  1735.               ------------     --------
  1736.               0     - 0.125       J
  1737.               0.125 - 0.375     Kish J
  1738.               0.375 - 0.5        J-K
  1739.         */
  1740.  
  1741.         hd = (ld * 10000L) / hd;
  1742.         if (hd < 1250L) {
  1743.             V strcat(cnstr, cixname(CV(huetab[j].purename)));
  1744.         } else if (hd < 3750L) {
  1745.             V strcat(cnstr, cixname(CV(huetab[k].ishname)));
  1746.             V strcat(cnstr, " ");
  1747.             V strcat(cnstr, cixname(CV(huetab[j].purename)));
  1748.         } else {
  1749.             V strcat(cnstr, cixname(CV(huetab[j].purename)));
  1750.             V strcat(cnstr, "-");
  1751.             V strcat(cnstr, cixname(CV(huetab[k].purename)));
  1752.         }
  1753.     }
  1754. }
  1755.  
  1756. /*  ACADRGB  --  Takes  an  AutoCAD  colour  number in hsv and returns
  1757.                  red, green, and blue intensities in rgp in the  range
  1758.                  0.0 to 1.0 */
  1759.  
  1760. static void acadrgb(int hsv, struct r_g_b *rgp)
  1761. {
  1762.     static ads_real brightfac[5] = {  /* Brightness levels */
  1763.        1.0, 0.65, 0.5, 0.3, 0.15
  1764.       }, halfsat = .5;                /* Halfway saturation */
  1765.     int ih, vs;
  1766.     ads_real h, s, f, value;
  1767.  
  1768.     // assert(hsv > 0 || hsv < 256);
  1769.  
  1770.     switch (hsv) {
  1771.     case BLACK:
  1772.         rgp->red   = 0.0;
  1773.         rgp->blue  = 0.0;
  1774.         rgp->green = 0.0;
  1775.         value = 0.0;
  1776.         break;
  1777.  
  1778.     case RED:
  1779.         rgp->red   = SAT;
  1780.         rgp->green = 0.0;
  1781.         rgp->blue  = 0.0;
  1782.         value = 1.0;
  1783.         break;
  1784.  
  1785.     case YELLOW:
  1786.         rgp->red   = SAT;
  1787.         rgp->green = SAT;
  1788.         rgp->blue  = 0.0;
  1789.         value = 1.0;
  1790.         break;
  1791.  
  1792.     case GREEN:
  1793.         rgp->red   = 0.0;
  1794.         rgp->green = SAT;
  1795.         rgp->blue  = 0.0;
  1796.         value = 1.0;
  1797.         break;
  1798.  
  1799.     case CYAN:
  1800.         rgp->red   = 0.0;
  1801.         rgp->green = SAT;
  1802.         rgp->blue  = SAT;
  1803.         value = 1.0;
  1804.         break;
  1805.  
  1806.     case BLUE:
  1807.         rgp->red   = 0.0;
  1808.         rgp->green = 0.0;
  1809.         rgp->blue  = SAT;
  1810.         value = 1.0;
  1811.         break;
  1812.  
  1813.     case MAGENTA:
  1814.         rgp->red   = SAT;
  1815.         rgp->green = 0.0;
  1816.         rgp->blue  = SAT;
  1817.         value = 1.0;
  1818.         break;
  1819.  
  1820.     case WHITE:
  1821.     case 8:
  1822.     case 9:
  1823.         rgp->red   = SAT;
  1824.         rgp->green = SAT;
  1825.         rgp->blue  = SAT;
  1826.         value = 1.0;
  1827.         break;
  1828.  
  1829.     default:
  1830.  
  1831.         /*  The chromatic colors.  The  hue  resulting  from  an
  1832.             AutoCAD color 10-249 will be determined by its first
  1833.             two digits, and the saturation and  value  from  the
  1834.             last digit, as follows:
  1835.  
  1836.             Hues:
  1837.  
  1838.              10 -- Red
  1839.              50 -- Yellow
  1840.              90 -- Green
  1841.             130 -- Cyan
  1842.             170 -- Blue
  1843.             210 -- Magenta
  1844.  
  1845.             Between  each  of these are three intermediate hues,
  1846.             e.g., between red and yellow, we have:
  1847.  
  1848.              20 -- reddish orange
  1849.              30 -- orange
  1850.              40 -- yellowish orange
  1851.  
  1852.             To each hue number, 0, 2, 4, 6, or 8 can be added to
  1853.             give a different "value", or brightness, with 0  the
  1854.             brightest  and  8  the  weakest.   Finally, 1 can be
  1855.             added to  produce  a  "half-saturated",  or  pastel,
  1856.             color.  For example, color 18 is the dimmest red and
  1857.             10 the brightest red.  19 is the dimmest pink and 11
  1858.             the brightest pink.
  1859.         */
  1860.  
  1861.         if (hsv > 9 && hsv < 250) {
  1862.  
  1863.             /* Apply the algorithm from Foley & van Dam to turn
  1864.                HSV into RGB values */
  1865.  
  1866.             ih = (hsv - 10) / 10;     /* Integer hue value. */
  1867.             if (ih >= 24)             /* Range is 0-23. */
  1868.                 ih -= 24;
  1869.             vs = hsv % 10;            /* Encoded value and saturation */
  1870.             h = ih / 4.;              /* Map into range [0.0,6.0) */
  1871.             ih = h;                   /* The integer part. */
  1872.             f = h - ih;               /* Fractional part. */
  1873.             value = brightfac[vs >> 1]; /* Value in [0,1] */
  1874.             s = vs & 1 ? halfsat : 1.0; /* Saturation */
  1875.  
  1876.             switch (ih) {
  1877.             case 0:
  1878.                 rgp->red   = 1.0;
  1879.                 rgp->green = (ads_real) (1.0 - s * (1.0 - f));
  1880.                 rgp->blue  = (ads_real) (1.0 - s);
  1881.                 break;
  1882.  
  1883.             case 1:
  1884.                 rgp->red   = (ads_real) (1.0 - s * f);
  1885.                 rgp->green = 1.0;
  1886.                 rgp->blue  = (ads_real) (1 - s);
  1887.                 break;
  1888.  
  1889.             case 2:
  1890.                 rgp->red   = (ads_real) (1.0 - s);
  1891.                 rgp->green = 1.0;
  1892.                 rgp->blue  = (ads_real) (1.0 - s *(1.0 - f));
  1893.                 break;
  1894.  
  1895.             case 3:
  1896.                 rgp->red   = (ads_real) (1.0 - s);
  1897.                 rgp->green = (ads_real) (1.0 - s * f);
  1898.                 rgp->blue  = 1.0;
  1899.                 break;
  1900.  
  1901.             case 4:
  1902.                 rgp->red   = (ads_real) (1.0 - s * (1.0 - f));
  1903.                 rgp->green = (ads_real) (1.0 - s);
  1904.                 rgp->blue  = 1.0;
  1905.                 break;
  1906.  
  1907.             case 5:
  1908.                 rgp->red   = 1.0;
  1909.                 rgp->green = (ads_real) (1.0 - s);
  1910.                 rgp->blue  = (ads_real) (1.0 - s * f);
  1911.                 break;
  1912.             }
  1913.         } else {
  1914.             /* Define some extra colours from dark grey to white
  1915.                in the 250 to 255 slots */
  1916.             value = 0.33 + (hsv - 250) * 0.134;
  1917.             rgp->red   = 1.0;
  1918.             rgp->green = 1.0;
  1919.             rgp->blue  = 1.0;
  1920.         }
  1921.         break;                        /* Default */
  1922.     }
  1923.     rgp->red   *= value;              /* Apply lightness scale factor */
  1924.     rgp->green *= value;              /* to components resulting from */
  1925.     rgp->blue  *= value;              /* hue and saturation. */
  1926. }
  1927.  
  1928. /*  RGBACAD  --  Find the AutoCAD colour closest to in RGB space to a
  1929.                  specified RGB triple.  */
  1930.  
  1931. static int rgbacad(ads_real r, ads_real g, ads_real b)
  1932. {
  1933.     int i, low, ccol;
  1934.     ads_real closest = 1000.0;
  1935.     struct r_g_b rc;
  1936.  
  1937.     // assert(r >= 0.0 && r <= 1.0);
  1938.     // assert(g >= 0.0 && g <= 1.0);
  1939.     // assert(b >= 0.0 && b <= 1.0);
  1940.  
  1941.     /* If we're mapping to the 8 colour gamut, turn all grey scale
  1942.        colours into white and map the rest based on hue alone. */
  1943.  
  1944.     if (gamut == 8) {
  1945.         ads_real h, s, v;
  1946.  
  1947.         rgb_hsv(r, g, b, &h, &s, &v);
  1948.         return s == 0.0 ? WHITE :
  1949.                (RED + ((((int) (h + 30.0)) % 360) / 60));
  1950.     }
  1951.  
  1952.     /* Note  that we start with  colour 1 since 0 (black) is not a
  1953.        valid user-specified colour.  If this is a grey scale tone,
  1954.        map only to AutoCAD's grey scale indices.  */
  1955.  
  1956.     ccol = low = (r == g && r == b) ? 250 : 1;
  1957.  
  1958.     for (i = low; i < 256; i++) {
  1959.         ads_real cdist;
  1960.  
  1961.         acadrgb(i, &rc);
  1962.         rc.red -= r;
  1963.         rc.green -= g;
  1964.         rc.blue -= b;
  1965.         cdist = rc.red * rc.red + rc.green * rc.green +
  1966.                 rc.blue * rc.blue;
  1967.         if (cdist < closest) {
  1968.             ccol = i;
  1969.             if ((closest = cdist) == 0.0)
  1970.                 break;
  1971.         }
  1972.     }
  1973.     if (ccol == 255)                  /* If synonym for white... */
  1974.         ccol = 7;                     /* ...make simple white. */
  1975.     return ccol;
  1976. }
  1977.  
  1978. /*  RETRGB  --  Return an RGB triple as either an RGB point or
  1979.                 the closest AutoCAD standard colour.  */
  1980.  
  1981. static void retrgb(Boolean acad, ads_real r, ads_real g, ads_real b)
  1982. {
  1983.     if (acad) {
  1984.         ads_retint(rgbacad(r, g, b));
  1985.     } else {
  1986.         ads_point p;
  1987.  
  1988.         Spoint(p, r, g, b);
  1989.         ads_retpoint(p);
  1990.     }
  1991. }
  1992.  
  1993. /*  TRIPLE  --  Scan  a  triple  of  real  arguments  into an array of
  1994.                 reals.  Integers are accepted and converted to  reals.
  1995.                 True  is  returned  if  valid  arguments are obtained;
  1996.                 False otherwise.  */
  1997.  
  1998. static Boolean triple(ads_real cdesc[3], Boolean rangecheck)
  1999. {
  2000.     int nargs;
  2001.     struct resbuf *rb1 = ads_getargs();
  2002.  
  2003.     ads_retnil();
  2004.     for (nargs = 0; nargs < 3; nargs++) {
  2005.         if (rb1 == NULL)
  2006.             break;
  2007.         if (rb1->restype == RTSHORT) {
  2008.             cdesc[nargs] = rb1->resval.rint;
  2009.         } else if (rb1->restype == RTREAL) {
  2010.             cdesc[nargs] = rb1->resval.rreal;
  2011.         } else if (nargs == 0 && rb1->restype == RT3DPOINT) {
  2012.             Cpoint(cdesc, rb1->resval.rpoint);
  2013.             nargs = 2;
  2014.         } else {
  2015.             ads_fail(/*MSG50*/"incorrect argument type");
  2016.             return False;
  2017.         }
  2018.         rb1 = rb1->rbnext;
  2019.     }
  2020.  
  2021.     /* Make sure there were enough arguments. */
  2022.  
  2023.     if (nargs < 3) {
  2024.         ads_fail(/*MSG51*/"too few arguments");
  2025.         return False;
  2026.     }
  2027.  
  2028.     /* Make sure there are no more arguments. */
  2029.  
  2030.     if (rb1 != NULL) {
  2031.         ads_fail(/*MSG52*/"too many arguments");
  2032.         return False;
  2033.     }
  2034.  
  2035.     /* Range check arguments if requested. */
  2036.  
  2037.     if (rangecheck) {
  2038.         for (nargs = 0; nargs < 3; nargs++) {
  2039.             if (rangecheck && (cdesc[nargs] < 0.0 || cdesc[nargs] > 1.0)) {
  2040.                 ads_fail(/*MSG53*/"argument out of range");
  2041.                 return False;
  2042.             }
  2043.         }
  2044.     }
  2045.  
  2046.     return True;
  2047. }
  2048.  
  2049. /*  CMY  --  Specify colour as CMY triple.  */
  2050.  
  2051. static void cmy(Boolean acad)
  2052. {
  2053.     ads_real cdesc[3];
  2054.  
  2055.     if (triple(cdesc, True)) {
  2056.         retrgb(acad, 1.0 - cdesc[0], 1.0 - cdesc[1],
  2057.                1.0 - cdesc[2]);
  2058.     }
  2059. }
  2060.  
  2061. /*  CTEMP  --  Specify colour as a colour temperature.  */
  2062.  
  2063. static void ctemp(Boolean acad)
  2064. {
  2065.     struct resbuf *rb;
  2066.  
  2067.     ads_retnil();
  2068.  
  2069.     if ((rb = ads_getargs()) == NULL) {
  2070.         ads_fail(/*MSG63*/"too few arguments");
  2071.     } else {
  2072.         ads_real degrees, ir, ig, ib;
  2073.  
  2074.         if (rb->restype == RTSHORT) {
  2075.             degrees = rb->resval.rint;
  2076.         } else if (rb->restype == RTREAL) {
  2077.             degrees = rb->resval.rreal;
  2078.         } else {
  2079.             ads_fail(/*MSG64*/"incorrect argument type");
  2080.             return;
  2081.         }
  2082.  
  2083.         /* Make sure there are no more arguments. */
  2084.  
  2085.         if (rb->rbnext != NULL) {
  2086.             ads_fail(/*MSG65*/"too many arguments");
  2087.             return;
  2088.         }
  2089.  
  2090.         ctemp_rgb(degrees, &ir, &ig, &ib);
  2091.         retrgb(acad, ir, ig, ib);
  2092.     }
  2093. }
  2094.  
  2095. /*  CNS  --  Specify colour as a CNS string.  */
  2096.  
  2097. static void cns(Boolean acad)
  2098. {
  2099.     struct resbuf *rb;
  2100.  
  2101.     ads_retnil();
  2102.  
  2103.     if ((rb = ads_getargs()) == NULL) {
  2104.         ads_fail(/*MSG54*/"too few arguments");
  2105.         return;
  2106.     } else {
  2107.         struct resbuf *rb1 = rb;
  2108.         ads_real ir, ig, ib;
  2109.  
  2110.         if (rb1->restype != RTSTR) {
  2111.             ads_fail(/*MSG55*/"incorrect argument type");
  2112.             return;
  2113.         }
  2114.  
  2115.         /* Make sure there are no more arguments. */
  2116.  
  2117.         if (rb1->rbnext != NULL) {
  2118.             ads_fail(/*MSG56*/"too many arguments");
  2119.             return;
  2120.         }
  2121.  
  2122.         if (cns_rgb(rb1->resval.rstring, &ir, &ig, &ib)) {
  2123.             retrgb(acad, ir, ig, ib);
  2124.         }
  2125.     }
  2126. }
  2127.  
  2128. /*  CNSER  --  Return string describing last CNS error, if any.  */
  2129.  
  2130. static void cnser()
  2131. {
  2132.     if (cnserr == NULL)
  2133.         ads_retnil();
  2134.     else
  2135.         ads_retstr(cnserr);
  2136. }
  2137.  
  2138. /*  HLS  --  Specify colour as HLS triple.  */
  2139.  
  2140. static void hls(Boolean acad)
  2141. {
  2142.     ads_real cdesc[3];
  2143.  
  2144.     if (triple(cdesc, True)) {
  2145.         ads_real ir, ig, ib;
  2146.  
  2147.         hls_rgb(cdesc[0] * 360.0, cdesc[1], cdesc[2], &ir, &ig, &ib);
  2148.         retrgb(acad, ir, ig, ib);
  2149.     }
  2150. }
  2151.  
  2152. /*  HSV  --  Specify colour as HSV triple.  */
  2153.  
  2154. static void hsv(Boolean acad)
  2155. {
  2156.     ads_real cdesc[3];
  2157.  
  2158.     if (triple(cdesc, True)) {
  2159.         ads_real ir, ig, ib;
  2160.  
  2161.         hsv_rgb(cdesc[0] * 360.0, cdesc[1], cdesc[2], &ir, &ig, &ib);
  2162.         retrgb(acad, ir, ig, ib);
  2163.     }
  2164. }
  2165.  
  2166. /*  RGB  --  Specify colour as RGB triple.  */
  2167.  
  2168. static void rgb( Boolean acad)
  2169. {
  2170.     ads_real cdesc[3];
  2171.  
  2172.     if (triple(cdesc, True)) {
  2173.         retrgb(acad, cdesc[0], cdesc[1], cdesc[2]);
  2174.     }
  2175. }
  2176.  
  2177. /*  YIQ  --  Specify colour as YIQ triple.  */
  2178.  
  2179. static void yiq(Boolean acad)
  2180. {
  2181.     ads_real cdesc[3];
  2182.  
  2183.     if (triple(cdesc, False)) {
  2184.         ads_real ir, ig, ib;
  2185.  
  2186.         if ((cdesc[0] < 0.0 || cdesc[0] > 1.0) &&
  2187.             (cdesc[1] < -0.6 || cdesc[0] > 0.6) &&
  2188.             (cdesc[2] < -0.52 || cdesc[2] > 0.52)) {
  2189.             ads_fail(/*MSG57*/"argument out of range");
  2190.         }
  2191.  
  2192.         yiq_rgb(cdesc[0], cdesc[1], cdesc[2], &ir, &ig, &ib);
  2193.  
  2194.         retrgb(acad, ir, ig, ib);
  2195.     }
  2196. }
  2197.  
  2198.  
  2199. /*  ACADCOL  --  Obtain AutoCAD colour.  We accept any of the following:
  2200.  
  2201.     1.  A single integer, representing an AutoCAD standard colour index.
  2202.     2.  A triple of reals and/or integers, representing RGB intensities.
  2203.     3.  A list of three reals and/or integers, representing RGB intensities.
  2204. */
  2205.  
  2206. static Boolean acadcol(struct r_g_b *rp)
  2207. {
  2208.     ads_real crgb[3];
  2209.     struct resbuf *rb = ads_getargs();
  2210.  
  2211.     ads_retnil();
  2212.  
  2213.     if (rb == NULL) {
  2214.         ads_fail(/*MSG58*/"too few arguments");
  2215.         return False;
  2216.     }
  2217.  
  2218.     if ((rb->restype == RTSHORT) && (rb->rbnext == NULL)) {
  2219.         int cindex = rb->resval.rint;
  2220.  
  2221.         if (cindex < 0 || cindex > 255) {
  2222.             ads_fail(/*MSG59*/"argument out of range");
  2223.             return False;
  2224.         }
  2225.         acadrgb(cindex, rp);
  2226.         return True;
  2227.     }
  2228.  
  2229.     if (triple(crgb, True)) {
  2230.         rp->red   = crgb[0];
  2231.         rp->green = crgb[1];
  2232.         rp->blue  = crgb[2];
  2233.     } else {
  2234.         return False;
  2235.     }
  2236.  
  2237.     return True;
  2238. }
  2239.  
  2240. /*  TORGB  --  Convert internal colour to RGB triple.  */
  2241.  
  2242. static void torgb()
  2243. {
  2244.     struct r_g_b rc;
  2245.  
  2246.     if (acadcol(&rc)) {
  2247.         ads_point p;
  2248.  
  2249.         Spoint(p, rc.red, rc.green, rc.blue);
  2250.         ads_retpoint(p);
  2251.     }
  2252. }
  2253.  
  2254. /*  TOCMY  --  Convert internal colour to CMY triple.  */
  2255.  
  2256. static void tocmy()
  2257. {
  2258.     struct r_g_b rc;
  2259.  
  2260.     if (acadcol(&rc)) {
  2261.         ads_point p;
  2262.  
  2263.         rgb_cmy(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2264.         ads_retpoint(p);
  2265.     }
  2266. }
  2267.  
  2268. /*  TOYIQ  --  Convert internal colour to YIQ triple.  */
  2269.  
  2270. static void toyiq()
  2271. {
  2272.     struct r_g_b rc;
  2273.  
  2274.     if (acadcol(&rc)) {
  2275.         ads_point p;
  2276.  
  2277.         rgb_yiq(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2278.         ads_retpoint(p);
  2279.     }
  2280. }
  2281.  
  2282. /*  TOHSV  --  Convert internal colour to HSV triple.  */
  2283.  
  2284. static void tohsv()
  2285. {
  2286.     struct r_g_b rc;
  2287.  
  2288.     if (acadcol(&rc)) {
  2289.         ads_point p;
  2290.  
  2291.         rgb_hsv(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2292.         p[X] = (p[X] < 0.0) ? 0.0 : (p[X] / 360.0);
  2293.         ads_retpoint(p);
  2294.     }
  2295. }
  2296.  
  2297. /*  TOHLS  --  Convert internal colour to HLS triple.  */
  2298.  
  2299. static void tohls()
  2300. {
  2301.     struct r_g_b rc;
  2302.  
  2303.     if (acadcol(&rc)) {
  2304.         ads_point p;
  2305.  
  2306.         rgb_hls(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2307.         p[X] = (p[X] < 0.0) ? 0.0 : (p[X] / 360.0);
  2308.         ads_retpoint(p);
  2309.     }
  2310. }
  2311.  
  2312. /*  TOCNS  --  Convert internal colour to CNS string.  */
  2313.  
  2314. static void tocns()
  2315. {
  2316.     struct r_g_b rc;
  2317.  
  2318.     if (acadcol(&rc)) {
  2319.         char cnstr[40];
  2320.  
  2321.         rgb_cns(rc.red, rc.green, rc.blue, cnstr);
  2322.         ads_retstr(cnstr);
  2323.     }
  2324. }
  2325.  
  2326. /*  COLSET  --  Set colour gamut available.  */
  2327.  
  2328. static void colset()
  2329. {
  2330.     struct resbuf *rb = ads_getargs();
  2331.  
  2332.     ads_retnil();
  2333.  
  2334.     if (rb == NULL) {
  2335.         ads_retint(gamut);
  2336.         return;
  2337.     }
  2338.  
  2339.     if (rb->rbnext != NULL) {
  2340.         ads_fail(/*MSG60*/"too many arguments");
  2341.         return;
  2342.     }
  2343.  
  2344.     if (rb->restype == RTSHORT) {
  2345.         int colsys = rb->resval.rint;
  2346.  
  2347.         switch (colsys) {
  2348.         case 8:
  2349.         case 256:
  2350.             gamut = colsys;
  2351.             ads_retint(gamut);
  2352.             break;
  2353.  
  2354.         default:
  2355.             ads_fail(/*MSG61*/"argument out of range");
  2356.         }
  2357.         return;
  2358.     }
  2359.     ads_fail(/*MSG62*/"incorrect argument type");
  2360. }
  2361.  
  2362.